package china.accountinghelper.business;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.xdroid.base.BusinessBase;

import china.wc.tallyhelper.database.SQLiteDALModelExpense;
import china.wc.tallyhelper.model.ModelBook;
import china.wc.tallyhelper.model.ModelExpense;
import china.wc.tallyhelper.model.ModelExpenseDetail;
import china.wc.tallyhelper.model.ModelPerson;
import com.xdroid.util.DateTimeUtil;

/**
 * 本类是所有业务类的父类，封装和ModelExpense实体类相关的业务逻辑。
 * 本类的作用是将DAL层的方法进一步封装，并将其返回结果进行必要的处理，方便Activity、Adapter进行调用。
 * 
 * @author 王超
 * 
 */
public class BusinessExpense extends BusinessBase<ModelExpense>
{
    private BusinessPerson mBusinessPerson = new BusinessPerson();
    private BusinessCategory mBusinessCategory = new BusinessCategory();
    private BusinessExpenseDetail mBusinessExpenseDetail = new BusinessExpenseDetail();

	public BusinessExpense()
	{
		super(new SQLiteDALModelExpense(ModelExpense.class));
	}

    public boolean insertModel(ModelExpense pModelObject, List<ModelExpenseDetail> pExpenseDetails)
    {
        boolean _Result = false;
        
        getSQLiteDAL().beginTransaction();
        try {
            insertModel(pModelObject);
            for (ModelExpenseDetail _ModelExpenseDetail : pExpenseDetails) {
                _ModelExpenseDetail.setExpenseID(pModelObject.getID());
                mBusinessExpenseDetail.insertModel(_ModelExpenseDetail);
            }
            getSQLiteDAL().setTransactionSuccessful();
            _Result = true;
        } finally {
            getSQLiteDAL().endTransaction();
        }
        
        return _Result;
    }
	
	public boolean updateModel(ModelExpense pModelObject,List<ModelExpenseDetail> pExpenseDetails)
	{
	    boolean _Result = false;
	    for (ModelExpenseDetail _ExpenseDetail : pExpenseDetails) {
            _ExpenseDetail.setExpenseID(pModelObject.getID());
        }
	    
	    getSQLiteDAL().beginTransaction();
	    try {
            boolean _1 = updateModel(pModelObject);
            boolean _2 = mBusinessExpenseDetail.deleteModel(mBusinessExpenseDetail.select(pModelObject));
            boolean _3 = mBusinessExpenseDetail.insertModel(pExpenseDetails);
            
            if (_1 && _2 && _3) {
                getSQLiteDAL().setTransactionSuccessful();
                _Result = true;
            }
        } finally {
            getSQLiteDAL().endTransaction();
        }
	    
	    return _Result;
	}
	
	public boolean insertOrUpdateModel(ModelExpense pExpense,List<ModelExpenseDetail> pExpenseDetails)
    {
        if (pExpense.getID()<=0) {
            return insertModel(pExpense, pExpenseDetails);
        } else {
            return updateModel(pExpense, pExpenseDetails);
        }
    }
	
	/**
	 * 传入账本，返回消费类别名称
	 */
	public String getCateoryName(ModelExpense pExpense)
    {
        return mBusinessCategory.select(pExpense.getCategoryID()).getName();
    }
	
	/**
	 * 传入账本，返回付款人姓名
	 */
	public String getPayerName(ModelExpense pExpense)
	{
	    return mBusinessPerson.select(pExpense.getPayerID()).getName();
	}
	
	/**
     * 传入账本，返回该账本的消费总额。
     * 单位为元。
     */
    public double count(ModelBook pBook)
    {
        List<ModelExpense> _Expenses = select(pBook);
        
        return count(_Expenses);
    }

    /**
     * 传入付款人、账本，返回该账本中、该付款人付款的消费总额。
     * 单位为元。
     */
    public double count(ModelBook pBook, ModelPerson pPayer)
    {
        List<ModelExpense> _Expenses = select(pBook,pPayer);
        
        return count(_Expenses);
    }

    /**
     * 返回该账本中，除该付款人外的所有消费记录的消费总额。
     * 单位为元。
     */
    public double countInvert(ModelBook pBook, ModelPerson pPayer)
    {
        List<ModelExpense> _Expenses = selectInvert(pBook,pPayer);
        
        return count(_Expenses);
    }

    /**
     * 传入账本，返回该账本中、自己付款的消费总额。
     * 单位为元。
     */
    public double countSelf(ModelBook pBook)
    {
        List<ModelExpense> _Expenses = selectSelf(pBook);
        return count(_Expenses);
    }

    /**
     * 传入账本，返回该账本中、不是自己付款的消费总额。
     * 单位为元。
     */
    public double countOthers(ModelBook pBook)
    {
        List<ModelExpense> _Expenses = selectOthers(pBook);
        return count(_Expenses);
    }

    /**
     * 计算在某账本中，所有人某一天内的消费总额。
     * 单位为元。
     */
    public double count(ModelBook pBook, Calendar pExpenseDate)
    {
        List<ModelExpense> _Expenses = select(pBook,pExpenseDate);
        return count(_Expenses);
    }
    
    /**
     * 传入账本，返回账本里所有的消费记录。按照消费日期倒序排序。
     * @param pBook
     * @return
     */
    public List<ModelExpense> select(ModelBook pBook)
    {
        String ColumnName1 = getSQLiteDAL().getFieldColumnMap().get("mBookID");
        String ColumnName2 = getSQLiteDAL().getFieldColumnMap().get("mExpenseDate");
        String _Selection = ColumnName1+"="+pBook.getID();
        String _OrderBy = ColumnName2+" "+"DESC";
        
        return getSQLiteDAL().select(_Selection, null, null, null, _OrderBy);
    }

    /**
     * 传入付款人、账本，返回该账本中、该付款人付款的消费记录。
     */
    public List<ModelExpense> select(ModelBook pBook, ModelPerson pPayer)
    {
        String ColumnName1 = getSQLiteDAL().getFieldColumnMap().get("mPayerID");
        String ColumnName2 = getSQLiteDAL().getFieldColumnMap().get("mBookID");
        String _Selection = ColumnName1+"="+pPayer.getID()+" "+"AND"+" "+ColumnName2+"="+pBook.getID();
        
        return getSQLiteDAL().select(_Selection, null, null, null, null);
    }

    /**
     * 返回该账本中，除该付款人外的所有消费记录。
     */
    public List<ModelExpense> selectInvert(ModelBook pBook, ModelPerson pPayer)
    {
        String ColumnName1 = getSQLiteDAL().getFieldColumnMap().get("mPayerID");
        String ColumnName2 = getSQLiteDAL().getFieldColumnMap().get("mBookID");
        String _Selection = ColumnName1+"!="+pPayer.getID()+" "+"AND"+" "+ColumnName2+"="+pBook.getID();
        
        return getSQLiteDAL().select(_Selection, null, null, null, null);
    }

    /**
     * 传入账本，返回该账本中、自己付款的消费记录。
     */
    public List<ModelExpense> selectSelf(ModelBook pBook)
    {
        ModelPerson _Payer = mBusinessPerson.selectSelf();
        return select(pBook, _Payer);
    }
    
    /**
     * 传入账本，返回该账本中、不是自己付款的消费记录。
     */
    public List<ModelExpense> selectOthers(ModelBook pBook)
    {
        ModelPerson _Payer = mBusinessPerson.selectSelf();
        return selectInvert(pBook, _Payer);
    }
    
    /**
     * 计算在某账本中，所有人某一天内的消费记录。
     */
    public List<ModelExpense> select(ModelBook pBook, Calendar pExpenseDate)
    {
        String ColumnName1 = getSQLiteDAL().getFieldColumnMap().get("mBookID");
        String ColumnName2 = getSQLiteDAL().getFieldColumnMap().get("mExpenseDate");
        
        String _Selection = ColumnName1+"="+pBook.getID()+" "+"AND"+" "+"date("+ColumnName2+"/1000,'unixepoch','localtime')"+"="+"'"+DateTimeUtil.getYearMonthDate1(pExpenseDate)+"'";
        
        return getSQLiteDAL().select(_Selection, null, null, null, null);
    }
    
    /**
     * 计算在某账本中，共有多少比消费记录
     * 
     * @param pBook
     * @return
     */
    public int howManyExpenses(ModelBook pBook)
    {
        String _Column = getSQLiteDAL().getFieldColumnMap().get("mBookID");
        String _Selection = _Column+"="+pBook.getID();
        
        return getSQLiteDAL().getCount(_Selection, null);
    }
    
    /**
     * 传入账本，返回一个Map对象，其中包含该账本中，各个付款人的付款金额合计。
     * @param pBook
     * @return
     */
    public Map<String, Double> statistics(ModelBook pBook)
    {
        List<ModelExpense> _Expenses = select(pBook);
        
        List<ModelPerson> _Payers = new ArrayList<ModelPerson>();
        for (ModelExpense _TemExpense : _Expenses) {
            ModelPerson _TemPayer = mBusinessPerson.select(_TemExpense.getPayerID());
            if (_Payers.contains(_TemPayer)) {
                continue;
            } else {
                _Payers.add(_TemPayer);
            }
        }
        
        Map<String, Double> _Map = new HashMap<String, Double>();
        for (ModelPerson _TemPerson : _Payers) {
            _Map.put(_TemPerson.getName(), count(pBook, _TemPerson));
        }
        
        return _Map;
    }
    
    /**
     * 传入ModelExpenseList，计算该List下所有Expense的消费总额。
     */
    private double count(List<ModelExpense> pExpenses)
    {
        double _Sum = 0;
        for (ModelExpense _TemExpense : pExpenses) {
            _Sum = _Sum+mBusinessExpenseDetail.count(_TemExpense);
        }
        return _Sum;
    }
    
}
